/**
 * 
 */
package taskTracker.ui.lwuit;

import java.util.Enumeration;

import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;

import com.sun.lwuit.Display;
import com.sun.lwuit.Form;
import com.sun.lwuit.events.ActionEvent;
import com.sun.lwuit.events.ActionListener;

import taskTracker.Project;
import taskTracker.Task;
import taskTracker.TimeEntries;

/**
 * Handles all jobs that need to be run in background
 * @author aseldawy
 *
 */
public class Background extends Timer implements ActionListener {
	
	/**59 seconds. We don't make an exact minute to avoid missing a minute*/
	private static final long ABOUT_MINUTE = 59 * 1000;

	/**The task that logs time in background*/
	private TimerTask logTimeTask;
	
	/**The task that shows a status alert to the user*/
	private TimerTask statusAlertTask;
	
	/**Singleton instance of this class*/
	public static final Background instance = new Background();

	/**The screen that shown the user the current status*/
	private StatusAlert statusAlert;

	/**The form that allows the user to log time*/
	private LogTimeForm logTimeForm;
	
	/**Last task chosen by user*/
	private Task currentTask;
	/**Last comment entered by user*/
	private String comment;

	/**Stores the screen that was shown before logging time/ showing status dialog*/
	private Form previousScreen;

	private Vector projects;
	
	private Background() {
		super();
		this.createLogTimeForm();
		this.createStatusAlertDialog();
	}
	
	private TimerTask createLogTimeTask() {
		return new TimerTask() {
			private long startLogTime;
			{
				startLogTime = System.currentTimeMillis();
			}
			// Schedule time to log time
			public void run() {
				TimeEntries.getInstance().logTime(currentTask, startLogTime, logTimeTask.scheduledExecutionTime(), comment);
				startLogTime = logTimeTask.scheduledExecutionTime();
			}
		};
	}

	private TimerTask createStatusAlertTask() {
		return new TimerTask() {
			// Show alert dialog at specified time
			public void run() {
				if (Display.getInstance().getCurrent() != logTimeForm && Display.getInstance().getCurrent() != statusAlert)
					previousScreen = Display.getInstance().getCurrent();
				// Its task may be running if the dialog was shown due to user input (not timer fire)
				statusAlertTask.cancel();
				statusAlertTask = null;

				Task[] topTasks = TimeEntries.getInstance().getLatestTasks(5);
				if (topTasks.length < 5) {
					Vector allTasks = new Vector();
					outer_loop:
					for (Enumeration e = projects.elements();e.hasMoreElements();) {
						Project p = (Project) e.nextElement();
						for (Enumeration f = p.getTasks().elements(); f.hasMoreElements();) {
							allTasks.addElement(f.nextElement());
							if (allTasks.size() >= 5) {
								break outer_loop;
							}
						}
					}
					topTasks = new Task[allTasks.size()];
					allTasks.copyInto(topTasks);
				}

				statusAlert.prepare(topTasks, comment, logTimeTask != null, currentTask);
				statusAlert.show();
			}
		};

	}

	/**
	 * Set current state to be logging time (true) or not logging time (false)
	 * @param logging
	 */
	public void startLogging(Task task, String comment, long alertInterval) {
		if (logTimeTask != null)
			throw new IllegalStateException("Already logging time");
		this.currentTask = task;
		this.comment = comment;
		this.logTimeTask = createLogTimeTask();
		this.schedule(logTimeTask, ABOUT_MINUTE, ABOUT_MINUTE);
		this.statusAlertTask = createStatusAlertTask();
		this.schedule(statusAlertTask, alertInterval);
	}
	
	private void stopLogging() {
		if (logTimeTask == null)
			throw new IllegalStateException("Not logging already");
		logTimeTask.cancel();
		logTimeTask = null;
	}

	public boolean isLogging() {
		return this.logTimeTask != null;
	}

	/**
	 * Changes how often {@link StatusAlert} dialog is shown to user.
	 * @param millis
	 */
	public void setNotificationPeriod(long alertInterval) {
		if (statusAlertTask != null)
			statusAlertTask.cancel();
		this.statusAlertTask = createStatusAlertTask();
		this.schedule(statusAlertTask, alertInterval, alertInterval);
	}
	
	private void createStatusAlertDialog() {
		this.statusAlert = new StatusAlert();
		statusAlert.addCommandListener(this);
	}
	
	private void createLogTimeForm() {
		this.logTimeForm = new LogTimeForm();
		logTimeForm.addCommandListener(this);
	}

	/**
	 * Prepares and shows the form that asks the user to log time
	 */
	public void showLogTimeForm() {
		if (statusAlertTask != null) {
			statusAlertTask.run();
		} else {
			this.logTimeForm.prepare(this.projects);
			if (Display.getInstance().getCurrent() != logTimeForm && Display.getInstance().getCurrent() != statusAlert)
				this.previousScreen = Display.getInstance().getCurrent();
			logTimeForm.show();
		}
	}

	public void setProjects(Vector projects) {
		this.projects = projects;
	}

	public void actionPerformed(ActionEvent ae) {
		com.sun.lwuit.Command c = ae.getCommand();
		if (this.logTimeForm != null && c == this.logTimeForm.cmdOk) {
			// Start logging
			this.startLogging(logTimeForm.getTask(), logTimeForm.getComment(), logTimeForm.getInterval());
			previousScreen.showBack();
		} else if (this.logTimeForm != null && c == this.logTimeForm.cmdCancel) {
			// Cancel logging time
			this.statusAlertTask = createStatusAlertTask();
			this.schedule(statusAlertTask, this.logTimeForm.getInterval());
			previousScreen.showBack();
		} else if (this.statusAlert != null && c == this.statusAlert.cmdStart) {
			startLogging(this.statusAlert.getTask(), this.statusAlert.getComment(), this.statusAlert.getInterval());
			previousScreen.showBack();
		} else if (this.statusAlert != null && c == this.statusAlert.cmdStop) {
			stopLogging();
			this.showLogTimeForm();
		} else if (this.statusAlert != null && c == this.statusAlert.cmdHide) {
			this.currentTask = this.statusAlert.getTask();
			this.comment = this.statusAlert.getComment();
			previousScreen.showBack();
			this.statusAlertTask = createStatusAlertTask();
			this.schedule(statusAlertTask, this.statusAlert.getInterval());
		}
	}
}
